#include "report.hpp"
#include<Arduino.h>
#include "../Global/GlobalDefs.hpp"
#include "../Global/globalVars.hpp"



#define MODE_OFFSET 15

void Report::init()
{
}

void Report::setClipStart()
{
	GlobalVars::timeMs = millis();
	if (GlobalVars::flagSimuRate != 0) {
		GlobalVars::timeMs *= GlobalVars::flagSimuRate;
	}
}

void Report::setClipEnd()
{
	GlobalVars::timeMs = 0;
}

const char* Report::reportMetadata() {
#define META_REPORT_FORMAT "Model:{%s}\r\n"                 \
/* 02 */                    "Identifier{%s}\r\n"			\
/* 01 */                    "UUID:{%016llx}\r\n"              
	uint64_t chipid = ESP.getEfuseMac();
	//Serial.println(DEV_MODEL);
	//Serial.println(chipid);
	//Serial.println(GlobalVars::identifier.c_str());
	//Serial.println("-------");

	sprintf(GlobalVars::outputBuffer, META_REPORT_FORMAT,
		/* 00 */		DEV_MODEL,
		/* 02 */		GlobalVars::identifier.c_str(),
		/* 01 */		chipid
	);
	return GlobalVars::outputBuffer;
}

#define PLATE GlobalVars::plateTemp
#define LPLATE GlobalVars::sampleLeftTemp
#define RPLATE GlobalVars::sampleRightTemp
#define CNT GlobalVars::containerTemp
#define PMP GlobalVars::pumpTemp
#define SUR GlobalVars::surroundingTemp
#define COR GlobalVars::coreTemp

const char* Report::reportState()
{
	float timeElapsedSec = (PLATE.readingTimeMs - GlobalVars::timeMs) / 1000.0f;

#define STATE_REPORT_FORMAT "%s-%s"								\
/* 01 */                    " by{%03d}|{%03d}@{%8.1f}"			\
/* 02 */                    ",Plt{%6.2f}to{%5.1f}"				\
/* 03 */                    ",Ctn{%6.2f}to{%5.1f}"				\
/* 04 */                    ",Pmp{%6.2f}to{%5.1f}"				\
/* 10 */                    ",Sur{%5.1f}"						\
/* 11 */                    ",Cor{%5.1f}"						\
/* 12 */                    ",Fan0@{%03d}rps"					\
/* 13 */                    ",Fan1@{%03d}rps"					\
/* 14 */                    ",Fan2@{%03d}rps"					\
/* 15 */                    "\r\n"
	sprintf(GlobalVars::outputBuffer, STATE_REPORT_FORMAT,
		/* 00 */    GlobalVars::controlMode2char(GlobalVars::ctrlPlan.tempFeedbackMode, GlobalVars::ctrlPlan.tempCtrlMode), ((GlobalVars::ctrlPlan.targetHoldStartMs == 0) ? "Chrg" : "Hold"),
		/* 01 */    GlobalVars::heatUpDrivePercent, GlobalVars::coolDownDrivePercent, timeElapsedSec,
		/* 02 */    PLATE.readingVal, PLATE.targetVal,
		/* 03 */    CNT.readingVal, CNT.targetVal,
		/* 04 */    PMP.readingVal, PMP.targetVal,
		/* 10 */    SUR.readingVal,
		/* 11 */    COR.readingVal,
		/* 12 */    GlobalVars::fanSpeedRPSs[0],
		/* 13 */    GlobalVars::fanSpeedRPSs[1],
		/* 14 */	GlobalVars::fanSpeedRPSs[2]
	/* 15 */);
	return GlobalVars::outputBuffer;
}
const char* Report::reporttest()
{
	float timeElapsedSec = (PLATE.readingTimeMs - GlobalVars::timeMs) / 1000.0f;
#define STATE_REPORT_FORMAT "%s-%s"							 \
/* 01 */                    " TIME@{%4.1f}"					 \
/* 02 */                    " HT{%03d}"						 \
/* 03 */                    "|CD{%03d}"						 \
/* 04 */					" Target{%3.2f}"				 \
/* 05 */                    ",Plt{%5.2f}"					 \
/* 06 */                    ",LPlt{%5.2f}"					 \
/* 07 */                    ",RPlt{%5.2f}"					 \
/* 08 */                    ",Ctn{%5.2f}"					 \
/* 09 */		            ",Pmp{%5.2f}"					 \
/* 11 */		            ",P{%5.2f},I{%5.2f},D{%5.2f}"    \
		                    "\r\n"
	sprintf(GlobalVars::outputBuffer, STATE_REPORT_FORMAT,
		/* 00 */    GlobalVars::controlMode2char(GlobalVars::ctrlPlan.tempFeedbackMode, GlobalVars::ctrlPlan.tempCtrlMode), ((GlobalVars::ctrlPlan.targetHoldStartMs == 0) ? "Chrg" : "Hold"),
		/* 01 */    timeElapsedSec,
		/* 02 */	GlobalVars::heatUpDrivePercent, GlobalVars::coolDownDrivePercent, 
		/* 04 */	GlobalVars::temptarget,
		/* 05 */    PLATE.readingVal,
		/* 06 */	LPLATE.readingVal,
		/* 07 */	RPLATE.readingVal,
		/* 08 */    CNT.readingVal,
		/* 09 */	PMP.readingVal,
		/* 11 */    GlobalVars::PIDoutputP, GlobalVars::PIDoutputI, GlobalVars::PIDoutputD
					);
	return GlobalVars::outputBuffer;
}

const char* Report::reportcurve()
{
	float timeElapsedSec = (PLATE.readingTimeMs - GlobalVars::timeMs) / 1000.0f;
#define	STATE_REPORT_FORMAT "Time:%6.2f,Temp:%6.2f,LTemp:%6.2f,RTemp:%6.2f,Pump:%6.2f\r\n"
	sprintf(GlobalVars::outputBuffer, STATE_REPORT_FORMAT,
		timeElapsedSec,
		PLATE.readingVal,
		LPLATE.readingVal,
		RPLATE.readingVal,
		PMP.readingVal
	);
	return GlobalVars::outputBuffer;
}

const char* Report::reportStartUpConfig() {
#define CONFIG_REPORT_START_UP_FORMAT "Start up with:"          \
																\
									  "\r\n~Mode:{%d}"			\
									  "\r\n~Target:{%4.2f}"		\
									  "\r\n~Verbose:{%d}"		\
																\
									  "\r\n"
	sprintf(GlobalVars::outputBuffer, CONFIG_REPORT_START_UP_FORMAT,
			GlobalVars::OnBoot::controlMode,
			GlobalVars::OnBoot::tempTarget,
			GlobalVars::OnBoot::verbose);
	return GlobalVars::outputBuffer;
}

#define CONFIG_REPORT_PID_FORMAT " control: P={%4.2f}, I={%4.2f}, D={%4.2f}, I-decay={%4.2f}"
#define CONFIG_REPORT_WARNING_FORMAT "\r\nWarning TempC:"	\
                             "\r\n  Plate: {%4.1f} ADD "	\
                             "\r\n  Cooler: {%4.1f}"		\
                             "\r\n  Container: {%4.1f}"		\
                             "\r\n  Surrounding: {%4.1f}"	\
                             "\r\n  Core: {%4.1f}"		

const char* reportPIDParasAndTemperatureThreshold(TemperatureController* curve, const char* name) {
	char* buffer = GlobalVars::outputBuffer;

	auto paraSet = (PIDController*)curve;
	size_t namePartLen = sprintf(buffer, name);

	buffer += namePartLen;
	size_t controlParaLen = sprintf(buffer, CONFIG_REPORT_PID_FORMAT, paraSet->kp, paraSet->ki, paraSet->kd, paraSet->errorForgetRatePerSec);

	buffer += controlParaLen;
	size_t warningTempsLen = sprintf(buffer, CONFIG_REPORT_WARNING_FORMAT,
		PLATE.warningThreshold,
		PMP.warningThreshold,
		CNT.warningThreshold,
		SUR.warningThreshold,
		COR.warningThreshold);

	buffer += warningTempsLen;
	sprintf(buffer, "\r\n");

	return GlobalVars::outputBuffer;
}

const char* Report::reportHeatUpConfig()
{
#ifdef CONTROL_BANGBANG
#define CONFIG_REPORT_HEAT_UP_FORMAT "Heat up curve:"           \
\
                             "\r\n  <{%4.2f} -> {%03d}%%"		\
                             "\r\n  <{%4.2f} -> {%03d}%%"		\
                             "\r\n  <{%4.2f} -> {%03d}%%"		\
                             "\r\n  <{%4.2f} -> {%03d}%%"		\
                             "\r\n   above  -> {%03d}%%"		\
\
                             "\r\nWarning TempC:"				\
\
                             "\r\n  Plate: {%4.1f}"				\
                             "\r\n  Cooler: {%4.1f}"			\
                             "\r\n  Container: {%4.1f}"		    \
                             "\r\n  Surrounding: {%4.1f}"       \
                             "\r\n  Core: {%4.1f}"				\
\
                             "\r\n"
	BangBangController* curve = (BangBangController*)GlobalVars::heatUpCurve;
	sprintf(GlobalVars::outputBuffer, CONFIG_REPORT_HEAT_UP_FORMAT,
		// ----
		curve->ptTempDiffC[0], curve->ptDrivePercent[0],
		curve->ptTempDiffC[1], curve->ptDrivePercent[1],
		curve->ptTempDiffC[2], curve->ptDrivePercent[2],
		curve->ptTempDiffC[3], curve->ptDrivePercent[3],
		curve->ptDrivePercent[4],
		// ----
		PLATE.warningThreshold,
		PMP.warningThreshold,
		CNT.warningThreshold,
		SUR.warningThreshold,
		COR.warningThreshold);
	return GlobalVars::outputBuffer;
#else
	return reportPIDParasAndTemperatureThreshold(GlobalVars::heatUpCurve, "Heat up");
#endif
}

const char* Report::reportHeatHoldConfig()
{
#ifdef CONTROL_BANGBANG
#define CONFIG_REPORT_HEAT_HOLD_FORMAT "Heat hold curve:"           \
\
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n   above  -> {%03d}%%" \
\
                             "\r\nWarning TempC:"       \
\
                             "\r\n  Plate: {%4.1f}"      \
                             "\r\n  Pump: {%4.1f}"        \
                             "\r\n  Container: {%4.1f}"        \
                             "\r\n  Surrounding: {%4.1f}"        \
                             "\r\n  Core: {%4.1f}"      \
\
                             "\r\n"
	BangBangController* curve = (BangBangController*)GlobalVars::heatHoldCurve;
	sprintf(GlobalVars::outputBuffer, CONFIG_REPORT_HEAT_HOLD_FORMAT,
		// ----
		curve->ptTempDiffC[0], curve->ptDrivePercent[0],
		curve->ptTempDiffC[1], curve->ptDrivePercent[1],
		curve->ptTempDiffC[2], curve->ptDrivePercent[2],
		curve->ptTempDiffC[3], curve->ptDrivePercent[3],
		curve->ptDrivePercent[4],
		// ----
		PLATE.warningThreshold,
		PMP.warningThreshold,
		CNT.warningThreshold,
		SUR.warningThreshold,
		COR.warningThreshold);
	return GlobalVars::outputBuffer;
#else
	return reportPIDParasAndTemperatureThreshold(GlobalVars::heatHoldCurve, "Heat hold");
#endif
}

const char* Report::reportCoolDownConfig()
{
#ifdef CONTROL_BANGBANG
#define CONFIG_REPORT_COOL_DOWN_FORMAT "Cool down curve:"           \
\
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n   above  -> {%03d}%%" \
\
                             "\r\n  Plate: {%4.1f}"      \
                             "\r\n  Cooler: {%4.1f}"        \
                             "\r\n  Container: {%4.1f}"        \
                             "\r\n  Surrounding: {%4.1f}"        \
                             "\r\n  Core: {%4.1f}"      \
\
                             "\r\n"
	BangBangController* curve = (BangBangController*)GlobalVars::coolDownCurve;
	sprintf(GlobalVars::outputBuffer, CONFIG_REPORT_COOL_DOWN_FORMAT,
		// ----
		curve->ptTempDiffC[0], curve->ptDrivePercent[0],
		curve->ptTempDiffC[1], curve->ptDrivePercent[1],
		curve->ptTempDiffC[2], curve->ptDrivePercent[2],
		curve->ptTempDiffC[3], curve->ptDrivePercent[3],
		curve->ptDrivePercent[4],
		// ----
		PLATE.warningThreshold,
		PMP.warningThreshold,
		CNT.warningThreshold,
		SUR.warningThreshold,
		COR.warningThreshold);
	return GlobalVars::outputBuffer;
#else
	return reportPIDParasAndTemperatureThreshold(GlobalVars::coolDownCurve, "Cool down");
#endif
}

const char* Report::reportCoolHoldConfig()
{
#ifdef CONTROL_BANGBANG
#define CONFIG_REPORT_COOL_HOLD_FORMAT "Cool hold curve:"           \
\
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n  <{%4.2f} -> {%03d}%%" \
                             "\r\n   above  -> {%03d}%%" \
\
                             "\r\n  Plate: {%4.1f}"      \
                             "\r\n  Cooler: {%4.1f}"        \
                             "\r\n  Container: {%4.1f}"        \
                             "\r\n  Surrounding: {%4.1f}"        \
                             "\r\n  Core: {%4.1f}"      \
\
                             "\r\n"
	BangBangController* curve = (BangBangController*)GlobalVars::coolHoldCurve;
	sprintf(GlobalVars::outputBuffer, CONFIG_REPORT_COOL_HOLD_FORMAT,
		// ----
		curve->ptTempDiffC[0], curve->ptDrivePercent[0],
		curve->ptTempDiffC[1], curve->ptDrivePercent[1],
		curve->ptTempDiffC[2], curve->ptDrivePercent[2],
		curve->ptTempDiffC[3], curve->ptDrivePercent[3],
		curve->ptDrivePercent[4],
		// ----
		PLATE.warningThreshold,
		PMP.warningThreshold,
		CNT.warningThreshold,
		SUR.warningThreshold,
		COR.warningThreshold);
	return GlobalVars::outputBuffer;
#else
	return reportPIDParasAndTemperatureThreshold(GlobalVars::coolHoldCurve, "Cool hold");
#endif
}

const char* Report::reportThermalModel() {
#define CONFIG_REPORT_THERMAL_MODEL_FORMAT "Thermal model:"           \
\
                             "\r\n  Plate-Holder HCap Ratio = {%4.3f}" \
\
                             "\r\n"
	sprintf(GlobalVars::outputBuffer, CONFIG_REPORT_THERMAL_MODEL_FORMAT,
		// ----
		GlobalVars::thermalModel.plateToHolderHeatCapacityRatio);
	return GlobalVars::outputBuffer;
}

const char* Report::reportChangeSpeed() {
#define CONFIG_REPORT_CHANGE_SPEED "Change Speed:{%4.3f}\r\n" 
	sprintf(GlobalVars::outputBuffer, CONFIG_REPORT_CHANGE_SPEED, GlobalVars::ctrlPlan.ChangeTempSpeed);
	return GlobalVars::outputBuffer;
}

const char* Report::reportModelAndUUID() {
#define CONFIG_REPORT_UUID_FORMAT DEV_MODEL		\
	"\r\nUUID:{%016llx}"           \
		"\r\n"
	uint64_t chipid = ESP.getEfuseMac();
	sprintf(GlobalVars::outputBuffer, CONFIG_REPORT_UUID_FORMAT,
		// ----
		chipid);
	return GlobalVars::outputBuffer;
}

const char* Report::reportBedTempAndOutput() {
	float timeElapsedSec = (PLATE.readingTimeMs - GlobalVars::timeMs) / 1000.0f;
	sprintf(GlobalVars::outputBuffer, "%8.1f,%03d,%03d,%4.2f\r\n",
		timeElapsedSec,
		GlobalVars::heatUpDrivePercent,
		GlobalVars::coolDownDrivePercent,
		PLATE.readingVal);
	return GlobalVars::outputBuffer;
}
